package rpc

import (
	"fmt"
	"errors"
	"strings"
	"net/url"
	"kumachan/standalone/rx"
	"kumachan/standalone/rpc/vd"
)


type Service struct {
	Identifier   ServiceIdentifier
	Constructor  ServiceConstructor
	Methods      map[string] ServiceMethod
}
type ServiceInterface struct {
	Identifier   ServiceIdentifier
	Constructor  ServiceConstructorInterface
	Methods      map[string] ServiceMethodInterface
}
type ServiceIndex  map[ServiceIdentifier] ServiceInterface

type ServiceIdentifier struct {
	Vendor   string
	Project  string
	Name     string
	Version  string
}
func MakeServiceIdentifier(vendor string, project string, name string, version string) ServiceIdentifier {
	return ServiceIdentifier {
		Vendor:  vendor,
		Project: project,
		Name:    name,
		Version: version,
	}
}
func (id ServiceIdentifier) String() string {
	return fmt.Sprintf (
		"%s:%s:%s:%s",
		url.QueryEscape(id.Vendor),
		url.QueryEscape(id.Project),
		url.QueryEscape(id.Name),
		url.QueryEscape(id.Version),
	)
}
func ParseServiceIdentifier(str string) (ServiceIdentifier, error) {
	var bad = (func() (ServiceIdentifier, error) {
		return ServiceIdentifier{}, errors.New("bad service identifier")
	})
	var t = strings.Split(str, ":")
	if len(t) != 4 { return bad() }
	var vendor, err0 = url.QueryUnescape(t[0])
	if err0 != nil { return bad() }
	var project, err1 = url.QueryUnescape(t[1])
	if err1 != nil { return bad() }
	var name, err2 = url.QueryUnescape(t[2])
	if err2 != nil { return bad() }
	var version, err3 = url.QueryUnescape(t[3])
	if err3 != nil { return bad() }
	return ServiceIdentifier {
		Vendor:  vendor,
		Project: project,
		Name:    name,
		Version: version,
	}, nil
}

type ServiceConstructor struct {
	ServiceConstructorInterface
	Impl ServiceConstructorImpl
}
type ServiceConstructorImpl func(vd.Object,Connection)(rx.Observable)
type ServiceConstructorInterface struct {
	ArgType  *vd.Type
}
type Connection interface {
	Close() error
	OnClose() rx.Observable
}

type ServiceMethod struct {
	ServiceMethodInterface
	Impl ServiceMethodImpl
}
type ServiceMethodImpl func(interface{},vd.Object)(rx.Observable)
type ServiceMethodInterface struct {
	ArgType     *vd.Type
	RetType     *vd.Type
	MultiValue  bool
}

